/*
 * Copyright ©2015-2021 Jaemon. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.gitee.jaemon.spring.adorner.core;

import io.gitee.jaemon.spring.adorner.annotation.ApiNote;
import io.gitee.jaemon.spring.adorner.annotation.GroupNote;
import io.gitee.jaemon.spring.adorner.exception.AdornerException;
import io.gitee.jaemon.spring.adorner.type.AnnotationPair;
import io.gitee.jaemon.spring.adorner.type.ApiDefinition;
import io.gitee.jaemon.spring.adorner.util.ClassUtils;
import io.gitee.jaemon.spring.adorner.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * 接口定义解析器
 *
 * @author Jaemon
 * @since 1.0
 */
public abstract class ApiDefinitionResolver<T> {
    /**
     * 参数处理器
     */
    private final ParamHandler<T> paramHandler;

    public ApiDefinitionResolver(ParamHandler<T> paramHandler) {
        this.paramHandler = paramHandler;
    }

    /**
     * 构造Api接口定义对象
     *
     * @param controller
     *      控制层类
     * @param urlPrefix
     *      地址前缀
     * @param order
     *      序号
     * @param method
     *      方法对象
     * @param annotationPair
     *      注解对
     * @return
     *      apiDefinition {@link ApiDefinition}
     * @throws AdornerException
     *      ex
     */
    public ApiDefinition<T> parse(
            Class<?> controller, String urlPrefix,
            int order, Method method,
            AnnotationPair<RequestMapping> annotationPair
    )throws AdornerException {
        String className = controller.getName();
        String groupName =
                (controller.isAnnotationPresent(GroupNote.class)) ?
                        controller.getAnnotation(GroupNote.class).value() :
                        DocContainer.CONTAINER.classGet(className, controller.getSimpleName());

        RequestMapping requestMapping = annotationPair.getAnnotation();
        String[] urlSuffixs;
        String name;
        Class<? extends Annotation> clazz = annotationPair.getBaseAnnotation().annotationType();
        try {
            name = (String) clazz.getDeclaredMethod("name").
                    invoke(annotationPair.getBaseAnnotation());
            urlSuffixs = (String[]) clazz.getDeclaredMethod("value").
                    invoke(annotationPair.getBaseAnnotation());
        } catch (
                IllegalAccessException | InvocationTargetException | NoSuchMethodException e
        ) {
            throw new AdornerException("反射调用类[%s]中value方法异常, message=%s.", clazz.getName(), e.getMessage());
        }

        String apiName =
                (method.isAnnotationPresent(ApiNote.class)) ?
                        method.getAnnotation(ApiNote.class).value() :
                        DocContainer.CONTAINER.methodGet(
                                className + ClassUtils.SPOT + method.getName(),
                                StringUtils.isEmpty(name) ? method.getName() : name
                        );

        // 请求地址
        String[] urls = urls(urlPrefix, urlPrefix(controller), urlSuffixs);

        // 请求方法
        RequestMethod[] requestMethods = requestMapping.method();
        if (requestMethods.length == 0) {
            requestMethods = RequestMethod.values();
        }

        // 请求体内容
        T request = paramHandler.requestHandler(method);

        // 响应体内容
        T response = paramHandler.responseHandler(method);

        return ApiDefinition.of(
                controller, method, groupName, apiName, urls, requestMethods, request, response, order
        );
    }


    /**
     * 接口地址集
     *
     * @param urlPrefix
     *          项目地址前缀
     * @param clazzUrls
     *          控制层地址集
     * @param methodUrls
     *          接口方法地址集
     * @return
     *      接口地址集
     */
    protected String[] urls(String urlPrefix, String[] clazzUrls, String[] methodUrls) {
        clazzUrls = clazzUrls == null || clazzUrls.length == 0 ?
                new String[]{""} : clazzUrls;
        methodUrls = methodUrls == null ?
                new String[]{} : methodUrls;

        int clazzUrlLength =
                clazzUrls.length > 1 ?
                        clazzUrls.length : 1,
                methodUrlLength =  methodUrls.length > 1 ?
                        methodUrls.length : 1;
        String[] result = new String[clazzUrlLength * methodUrlLength];

        for (int i = 0; i < clazzUrls.length; i++) {
            String clazzUrl = ClassUtils.urlFormat(clazzUrls[i]);
            for (int j = 0, length = methodUrls.length; j < length; j++) {
                String methodUrl = ClassUtils.urlFormat(methodUrls[j]);
                result[i * length + j] = urlPrefix + clazzUrl + methodUrl;
            }
        }

        return result;
    }


    /**
     * 地址前缀
     *
     * @param clazz
     *      控制类
     * @return
     *      地址信息
     */
    protected String[] urlPrefix(Class<?> clazz) {
        if (clazz.isAnnotationPresent(RequestMapping.class)) {
            RequestMapping requestMapping = clazz.getAnnotation(RequestMapping.class);
            String[] value = requestMapping.value();
            return ClassUtils.urlsFormat(value);
        }
        return new String[]{""};
    }
}